/*
 * @Author: lixu lixu@puchigames.com
 * @Date: 2025-09-18 10:10:00
 * @LastEditors: lixu lixu@puchigames.com
 * @LastEditTime: 2025-09-18 10:10:00
 * @FilePath: /go-helper/utils/net.go
 * @Description: 网络工具函数，包含IP处理、网络检测等功能
 */

package ixUtils

import (
	"context"
	"fmt"
	"io"
	"net"
	"net/http"
	"strconv"
	"strings"
	"time"
)

// ========== IP处理函数 ==========

// GetLocalIP 获取本机内网IP地址
func GetLocalIP() string {
	addrs, err := net.InterfaceAddrs()
	if err != nil {
		return ""
	}

	for _, addr := range addrs {
		if ipNet, ok := addr.(*net.IPNet); ok && !ipNet.IP.IsLoopback() {
			if ipNet.IP.To4() != nil {
				return ipNet.IP.String()
			}
		}
	}
	return ""
}

// GetLocalIPs 获取本机所有内网IP地址
func GetLocalIPs() []string {
	var ips []string
	addrs, err := net.InterfaceAddrs()
	if err != nil {
		return ips
	}

	for _, addr := range addrs {
		if ipNet, ok := addr.(*net.IPNet); ok && !ipNet.IP.IsLoopback() {
			if ipNet.IP.To4() != nil {
				ips = append(ips, ipNet.IP.String())
			}
		}
	}
	return ips
}

// GetPublicIP 获取公网IP地址
func GetPublicIP() string {
	// 尝试多个服务，提高成功率
	urls := []string{
		"https://api.ipify.org",
		"https://ifconfig.me",
		"https://icanhazip.com",
		"https://ident.me",
	}

	client := &http.Client{
		Timeout: 10 * time.Second,
	}

	for _, url := range urls {
		resp, err := client.Get(url)
		if err != nil {
			continue
		}
		defer resp.Body.Close()

		if resp.StatusCode == http.StatusOK {
			body, err := io.ReadAll(resp.Body)
			if err != nil {
				continue
			}
			ip := strings.TrimSpace(string(body))
			if IsValidIP(ip) {
				return ip
			}
		}
	}
	return ""
}

// IsPrivateIP 检查是否为私有IP地址
func IsPrivateIP(ip string) bool {
	if !IsValidIP(ip) {
		return false
	}

	parsedIP := net.ParseIP(ip)
	if parsedIP == nil {
		return false
	}

	// 检查IPv4私有地址范围
	if parsedIP.To4() != nil {
		// 10.0.0.0/8
		if parsedIP[12] == 10 {
			return true
		}
		// 172.16.0.0/12
		if parsedIP[12] == 172 && parsedIP[13] >= 16 && parsedIP[13] <= 31 {
			return true
		}
		// 192.168.0.0/16
		if parsedIP[12] == 192 && parsedIP[13] == 168 {
			return true
		}
		// 127.0.0.0/8 (loopback)
		if parsedIP[12] == 127 {
			return true
		}
	}

	return false
}

// IsPublicIP 检查是否为公网IP地址
func IsPublicIP(ip string) bool {
	if !IsValidIP(ip) {
		return false
	}
	return !IsPrivateIP(ip)
}

// IPToInt 将IP地址转换为32位无符号整数
func IPToInt(ip string) uint32 {
	if !IsValidIP(ip) {
		return 0
	}

	parsedIP := net.ParseIP(ip)
	if parsedIP == nil {
		return 0
	}

	// 转换为IPv4
	ipv4 := parsedIP.To4()
	if ipv4 == nil {
		return 0
	}

	return uint32(ipv4[0])<<24 + uint32(ipv4[1])<<16 + uint32(ipv4[2])<<8 + uint32(ipv4[3])
}

// IntToIP 将32位无符号整数转换为IP地址
func IntToIP(ipInt uint32) string {
	return fmt.Sprintf("%d.%d.%d.%d",
		byte(ipInt>>24),
		byte(ipInt>>16),
		byte(ipInt>>8),
		byte(ipInt))
}

// IsValidIP 检查IP地址格式是否有效
func IsValidIP(ip string) bool {
	return net.ParseIP(ip) != nil
}

// IsValidIPv4 检查是否为有效的IPv4地址
func IsValidIPv4(ip string) bool {
	parsedIP := net.ParseIP(ip)
	return parsedIP != nil && parsedIP.To4() != nil
}

// IsValidIPv6 检查是否为有效的IPv6地址
func IsValidIPv6(ip string) bool {
	parsedIP := net.ParseIP(ip)
	return parsedIP != nil && parsedIP.To4() == nil
}

// ========== 网络检测函数 ==========

// Ping 检测主机是否可达（使用TCP连接测试）
func Ping(host string) bool {
	return PingWithTimeout(host, 3*time.Second)
}

// PingWithTimeout 带超时的Ping检测
func PingWithTimeout(host string, timeout time.Duration) bool {
	// 如果没有指定端口，使用80端口
	if !strings.Contains(host, ":") {
		host = host + ":80"
	}

	conn, err := net.DialTimeout("tcp", host, timeout)
	if err != nil {
		return false
	}
	defer conn.Close()
	return true
}

// IsPortOpen 检查指定主机的端口是否开放
func IsPortOpen(host string, port int) bool {
	return IsPortOpenWithTimeout(host, port, 3*time.Second)
}

// IsPortOpenWithTimeout 带超时的端口检测
func IsPortOpenWithTimeout(host string, port int, timeout time.Duration) bool {
	address := net.JoinHostPort(host, strconv.Itoa(port))
	conn, err := net.DialTimeout("tcp", address, timeout)
	if err != nil {
		return false
	}
	defer conn.Close()
	return true
}

// ScanPorts 扫描主机的端口范围
func ScanPorts(host string, startPort, endPort int) []int {
	return ScanPortsWithTimeout(host, startPort, endPort, 1*time.Second)
}

// ScanPortsWithTimeout 带超时的端口扫描
func ScanPortsWithTimeout(host string, startPort, endPort int, timeout time.Duration) []int {
	var openPorts []int

	for port := startPort; port <= endPort; port++ {
		if IsPortOpenWithTimeout(host, port, timeout) {
			openPorts = append(openPorts, port)
		}
	}

	return openPorts
}

// GetDomainIP 获取域名对应的IP地址列表
func GetDomainIP(domain string) []string {
	return GetDomainIPWithTimeout(domain, 5*time.Second)
}

// GetDomainIPWithTimeout 带超时的域名解析
func GetDomainIPWithTimeout(domain string, timeout time.Duration) []string {
	var ips []string

	// 创建带超时的解析器
	resolver := &net.Resolver{
		PreferGo: true,
		Dial: func(ctx context.Context, network, address string) (net.Conn, error) {
			d := net.Dialer{
				Timeout: timeout,
			}
			return d.DialContext(ctx, network, address)
		},
	}

	addrs, err := resolver.LookupIPAddr(context.TODO(), domain)
	if err != nil {
		return ips
	}

	for _, addr := range addrs {
		ips = append(ips, addr.IP.String())
	}

	return ips
}

// GetDomainIPv4 获取域名对应的IPv4地址列表
func GetDomainIPv4(domain string) []string {
	allIPs := GetDomainIP(domain)
	var ipv4s []string

	for _, ip := range allIPs {
		if IsValidIPv4(ip) {
			ipv4s = append(ipv4s, ip)
		}
	}

	return ipv4s
}

// GetDomainIPv6 获取域名对应的IPv6地址列表
func GetDomainIPv6(domain string) []string {
	allIPs := GetDomainIP(domain)
	var ipv6s []string

	for _, ip := range allIPs {
		if IsValidIPv6(ip) {
			ipv6s = append(ipv6s, ip)
		}
	}

	return ipv6s
}

// ========== 网络信息获取 ==========

// GetMACAddress 获取本机MAC地址
func GetMACAddress() string {
	interfaces, err := net.Interfaces()
	if err != nil {
		return ""
	}

	for _, inter := range interfaces {
		// 跳过loopback和down状态的接口
		if inter.Flags&net.FlagLoopback == 0 && inter.Flags&net.FlagUp != 0 {
			if len(inter.HardwareAddr) > 0 {
				return inter.HardwareAddr.String()
			}
		}
	}
	return ""
}

// GetAllMACAddresses 获取所有网络接口的MAC地址
func GetAllMACAddresses() map[string]string {
	macAddrs := make(map[string]string)
	interfaces, err := net.Interfaces()
	if err != nil {
		return macAddrs
	}

	for _, inter := range interfaces {
		if len(inter.HardwareAddr) > 0 {
			macAddrs[inter.Name] = inter.HardwareAddr.String()
		}
	}
	return macAddrs
}

// GetNetworkInterfaces 获取网络接口信息
func GetNetworkInterfaces() []NetworkInterface {
	var interfaces []NetworkInterface
	netInterfaces, err := net.Interfaces()
	if err != nil {
		return interfaces
	}

	for _, inter := range netInterfaces {
		addrs, err := inter.Addrs()
		if err != nil {
			continue
		}

		var ips []string
		for _, addr := range addrs {
			if ipNet, ok := addr.(*net.IPNet); ok {
				ips = append(ips, ipNet.IP.String())
			}
		}

		interfaces = append(interfaces, NetworkInterface{
			Name:         inter.Name,
			HardwareAddr: inter.HardwareAddr.String(),
			Flags:        inter.Flags.String(),
			MTU:          inter.MTU,
			IPs:          ips,
		})
	}

	return interfaces
}

// NetworkInterface 网络接口信息结构
type NetworkInterface struct {
	Name         string   `json:"name"`
	HardwareAddr string   `json:"hardware_addr"`
	Flags        string   `json:"flags"`
	MTU          int      `json:"mtu"`
	IPs          []string `json:"ips"`
}

// ========== 网络工具函数 ==========

// IsValidPort 检查端口号是否有效
func IsValidPort(port int) bool {
	return port > 0 && port <= 65535
}

// IsValidDomain 检查域名格式是否有效（简单检查）
func IsValidDomain(domain string) bool {
	if len(domain) == 0 || len(domain) > 253 {
		return false
	}

	// 基本格式检查
	if strings.HasPrefix(domain, ".") || strings.HasSuffix(domain, ".") {
		return false
	}

	parts := strings.Split(domain, ".")
	if len(parts) < 2 {
		return false
	}

	for _, part := range parts {
		if len(part) == 0 || len(part) > 63 {
			return false
		}
		// 简单的字符检查
		for _, r := range part {
			if !((r >= 'a' && r <= 'z') || (r >= 'A' && r <= 'Z') ||
				(r >= '0' && r <= '9') || r == '-') {
				return false
			}
		}
	}

	return true
}

// GetFreePort 获取一个可用的端口号
func GetFreePort() (int, error) {
	addr, err := net.ResolveTCPAddr("tcp", "localhost:0")
	if err != nil {
		return 0, err
	}

	l, err := net.ListenTCP("tcp", addr)
	if err != nil {
		return 0, err
	}
	defer l.Close()

	return l.Addr().(*net.TCPAddr).Port, nil
}

// IsLocalhost 检查是否为本地地址
func IsLocalhost(host string) bool {
	return host == "localhost" || host == "127.0.0.1" || host == "::1"
}

// NormalizeHost 标准化主机地址（移除端口）
func NormalizeHost(hostPort string) string {
	host, _, err := net.SplitHostPort(hostPort)
	if err != nil {
		return hostPort // 如果没有端口，直接返回
	}
	return host
}

// JoinHostPort 组合主机和端口
func JoinHostPort(host string, port int) string {
	return net.JoinHostPort(host, strconv.Itoa(port))
}

// ParseHostPort 解析主机和端口
func ParseHostPort(hostPort string) (host string, port int, err error) {
	host, portStr, err := net.SplitHostPort(hostPort)
	if err != nil {
		return "", 0, err
	}

	port, err = strconv.Atoi(portStr)
	if err != nil {
		return "", 0, err
	}

	return host, port, nil
}

// ========== 网络测试工具 ==========

// TestConnection 测试网络连接
type ConnectionTest struct {
	Host     string        `json:"host"`
	Port     int           `json:"port"`
	Protocol string        `json:"protocol"`
	Success  bool          `json:"success"`
	Duration time.Duration `json:"duration"`
	Error    string        `json:"error,omitempty"`
}

// TestTCPConnection 测试TCP连接
func TestTCPConnection(host string, port int) ConnectionTest {
	start := time.Now()
	test := ConnectionTest{
		Host:     host,
		Port:     port,
		Protocol: "tcp",
	}

	conn, err := net.DialTimeout("tcp", JoinHostPort(host, port), 5*time.Second)
	test.Duration = time.Since(start)

	if err != nil {
		test.Success = false
		test.Error = err.Error()
	} else {
		test.Success = true
		conn.Close()
	}

	return test
}

// TestUDPConnection 测试UDP连接
func TestUDPConnection(host string, port int) ConnectionTest {
	start := time.Now()
	test := ConnectionTest{
		Host:     host,
		Port:     port,
		Protocol: "udp",
	}

	conn, err := net.DialTimeout("udp", JoinHostPort(host, port), 5*time.Second)
	test.Duration = time.Since(start)

	if err != nil {
		test.Success = false
		test.Error = err.Error()
	} else {
		test.Success = true
		conn.Close()
	}

	return test
}

// BatchTestConnections 批量测试连接
func BatchTestConnections(hosts []string, ports []int) []ConnectionTest {
	var results []ConnectionTest

	for _, host := range hosts {
		for _, port := range ports {
			result := TestTCPConnection(host, port)
			results = append(results, result)
		}
	}

	return results
}
